#include <netinet/in.h>
#include "download.h"
#include "exceptions.h"
#include "peer_connection.h"

#define BUFFER_SIZE (1 << 9)

namespace torrent {

void PeerConnection::set(int fd, const Peer& p, Download* d) {
	if (m_fd >= 0)
		throw internal_error("Tried to re-set PeerConnection");

	m_fd = fd;
	m_peer = p;
	m_download = d;

	if (d == NULL ||
		!p.valid() ||
		m_fd < 0)
		throw internal_error("PeerConnection set received bad input");

	// Set the bitfield size and zero it
	m_bitfield = BitField(d->files().chunkCount());

	insertRead();
	insertWrite();
	insertExcept();

	makeBuf(&m_up.buf, BUFFER_SIZE);
	makeBuf(&m_down.buf, BUFFER_SIZE);

	if (!d->files().bitfield().zero()) {
		// Send bitfield to peer.
		bufCmd(BITFIELD, 1 + m_download->files().bitfield().sizeBytes(), 1);
		m_up.pos = 0;
		m_up.state = WRITE_MSG;
	}

	insertService(Timer::current() + 120 * 1000000, SERVICE_KEEP_ALIVE);

	m_lastChoked = Timer::current() - 10 * 1000000; // 10s
	m_lastMsg = Timer::current();
}

void PeerConnection::read() {
}

void PeerConnection::write() {
}

void PeerConnection::except() {
}

int PeerConnection::fd() {
	return m_fd;
}

PeerConnection::PeerConnection() :
	m_fd(-1),
	m_shutdown(false),

	m_download(NULL),

	m_sendChoked(false),
	m_sendInterested(false),
	m_sendBitfield(false)
{
}

PeerConnection::~PeerConnection() {
	// TODO Auto-generated destructor stub
}

bool PeerConnection::chokeDelayed() {
	return m_sendChoked || inService(SERVICE_SEND_CHOKE);
}

void PeerConnection::bufCmd(Protocol cmd, unsigned int length,
		unsigned int send) {
	m_up.pos = m_up.length;
	m_up.length += (send ? send : length) + 4;

	if (m_up.length > BUFFER_SIZE)
		throw internal_error("PeerConnection write buffer to small");

	*(uint32_t*)(m_up.buf + m_up.pos) = htonl(length);

	m_up.buf[(m_up.pos += 4)++] = cmd;
	m_up.lastCommand = cmd;
}

} // namespace torrent
